package gui;

import commands.controller.CC_GUIMoveDownloadTask;
import commands.controller.CC_GUIStartDownloadFile;
import commands.controller.CC_GUIStopDownloadFile;
import gui.refresher.WrongValue;
import gui.refresher.Refresher;
import gui.refresher.RefresherTask;
import commands.controller.ControllerCommand;
import commands.gui.GUICommand;
import commands.gui.GUICurrentPreferences;
import commands.gui.GUIDownloadError;
import commands.gui.GUIDownloadFinished;
import commands.gui.GUIDownloadStatusAll;
import commands.gui.GUIHostActive;
import commands.gui.GUISearchResult;
import commands.gui.GUISharedFilesList;
import controller.Controller;
import dataTypes.DownloadFile;
import dataTypes.File;
import dataTypes.Host;
import gui.dataTypes.DownloadTask;
import java.io.PrintStream;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.concurrent.LinkedBlockingQueue;

/**
 *
 * @author soldier
 */
public class GUI implements Runnable {

    private final P2pApp manager;
    private final LinkedBlockingQueue<GUICommand> inputQueue;
    private final Controller ctrl;
    private final PrintStream logPrint;
    private final PrintStream errPrint;
    private Refresher cron = null;

    public GUI(Controller ctrl) {
        logPrint = System.out;
        errPrint = System.err;
        logPrint.println("Gui: constructor call");
        inputQueue = new LinkedBlockingQueue<GUICommand>();
        this.ctrl = ctrl;
        P2pApp.launch(null);
        manager = P2pApp.getManager();
        manager.setGUICtrl(this);
        inStart();
    }

    public void run() {
        GUICommand cmd;
        boolean error = false;
        while (true) {
            try {
                cmd = inputQueue.take();
                logPrint.println("GUI: run(): read new cmd: " + cmd.getCommandType());
                switch (cmd.getCommandType()) {
                    case CLEAR_DOWNLOAD_LIST:
                        inClearDownloadList();
                        break;
                    case CLEAR_SHARED_LIST:
                        inClearShareList();
                        break;
                    case DOWNLOADS_STATUS:
                        if (cmd instanceof GUIDownloadStatusAll) {
                            GUIDownloadStatusAll stCmd = (GUIDownloadStatusAll) cmd;
                            inDownloadStatusAll(stCmd);
                        } else {
                            error = true;
                        }
                        break;
                    case SHARED_FILES_LIST:
                        if (cmd instanceof GUISharedFilesList) {
                            GUISharedFilesList stCmd = (GUISharedFilesList) cmd;
                            inSharedFiles(stCmd);
                        } else {
                            error = true;
                        }
                        break;
                    case PREFERENCES:
                        if (cmd instanceof GUICurrentPreferences) {
                            GUICurrentPreferences propCmd = (GUICurrentPreferences) cmd;
                            inCurrentPreferences(propCmd);
                        }
                        break;
                    case EXIT:
                        //inExit();
                        break;
                    case SEARCH_RESULT:
                        if (cmd instanceof GUISearchResult) {
                            GUISearchResult searchResultCmd = (GUISearchResult) cmd;
                            inSearchResult(searchResultCmd);
                        } else {
                            error = true;
                        }
                        break;
                    case HOST_ACTIVE:
                        if (cmd instanceof GUIHostActive) {
                            GUIHostActive activeHostCmd = (GUIHostActive) cmd;
                            inHostActive(activeHostCmd);
                        }
                        break;
                    case STARTED:
                        inStart();
                        break;
                    case STOPED:
                        inStop();
                        break;
                    case ERROR:
                        if (cmd instanceof GUIDownloadError) {
                            GUIDownloadError errorCmd = (GUIDownloadError) cmd;
                            inError(errorCmd);
                        }
                        break;
                    case FINISHED:
                        if (cmd instanceof GUIDownloadFinished) {
                            GUIDownloadFinished finishedCmd = (GUIDownloadFinished) cmd;
                            inDownloadFinished(finishedCmd);
                        }
                        break;
                    default:
                        logPrint.println("GUI: run(): unknown message type");
                }
                if (error) {
                    logPrint.print("");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Write command to GUI
     * @param cmd Command to write
     * @throws java.lang.InterruptedException if interrupted while waiting
     */
    public void writeMsg(GUICommand cmd) throws InterruptedException {
        synchronized (inputQueue) {
            if (inputQueue.remainingCapacity() == 0) {
                logPrint.println("GUI: writeMsg(): input queue is full - blocking call");
            }
            inputQueue.put(cmd);
        }
    }

    protected void writeOutCommand(ControllerCommand cc) {
        // TODO: call controler writing method
        logPrint.println("GUI: write to controler: " + cc.getCommandType() + "\n");
        try {
            ctrl.writeMsg(cc);
        } catch (InterruptedException e) {
            errPrint.println("GUI: cannot write to controller");
            e.printStackTrace(errPrint);
        }
    }

    private void inDownloadStatusAll(GUIDownloadStatusAll cmd) {
        manager.validateDownloading(cmd.getFiles());

        if (manager.isAllStoped()) {
            cron.stopTask();
        } else {
            cron.wakeTask();
        }
    }

    private void inSharedFiles(GUISharedFilesList cmd) {
        manager.validateShared(cmd.getSharedFilesList());
    }

    private void inHostActive(GUIHostActive cmd) {
        manager.addHostToActive(cmd.getHost().getHostName());
    }

    private void inSearchResult(GUISearchResult cmd) {
        File file;
        for (ListIterator<File> iter = cmd.getIterator(); iter.hasNext();) {
            file = iter.next();
            manager.addSearchResult(cmd.getIdSearch(), file, cmd.getHost());
        }
    }

    private void inStop() {
        if (cron != null) {
            cron.stopTask();
            cron = null;
        } else {
            errPrint.println("GUI: inStop(): cron is null");
        }
    }

    private void inStart() {
        if (cron != null) {
            errPrint.println("GUI: inStart(): cron is working");
        }
        try {
            Object obj[] = new Object[1];
            obj[0] = this;
            cron = new Refresher(new RefresherTask() {

                private GUI gui;

                public void doTask() {
                    gui.writeOutCommand(new ControllerCommand(
                            ControllerCommand.ControllerCommandType.GUI_REFRESH_DOWNLOAD_STATUS_ALL));
                }

                public void initTask(Object[] obj) {
                    System.out.println("Refresher init call");
                    if (obj != null &&
                            obj.length == 1 &&
                            obj[0] instanceof GUI) {
                        gui = (GUI) obj[0];
                    } else {
                        throw new UnsupportedOperationException("Wrong args");
                    }
                }
            },
                    obj,
                    5000);
            cron.start();
        } catch (WrongValue e) {
            e.printStackTrace();
        }
    }

    private void inClearDownloadList() {
        manager.clearDownloadTable();
    }

    private void inClearShareList() {
        manager.clearSharedTable();
    }

    private void inCurrentPreferences(GUICurrentPreferences cmd) {
        manager.displayPropertiesWin(cmd.getMaxActiveDownloads(),
                cmd.getConnectionsPerDownload());
    }

    private void inError(GUIDownloadError cmd) {
        manager.displayErrorWin(cmd.getFile().getPath(), cmd.getMessage());
    }

    private void inDownloadFinished(GUIDownloadFinished cmd) {
        manager.displayDownloadFinished(cmd.getFile().getPath());
    }
}
